package ru.amse.tsyganov.jumleditor.validator;

import java.util.HashSet;
import java.util.Set;

import ru.amse.tsyganov.jumleditor.main.ChartType;
import ru.amse.tsyganov.jumleditor.model.common.Edge;
import ru.amse.tsyganov.jumleditor.model.common.GraphModel;
import ru.amse.tsyganov.jumleditor.model.common.State;
import ru.amse.tsyganov.jumleditor.view.SelectedItems;
import ru.amse.tsyganov.jumleditor.view.Validity;
import ru.amse.tsyganov.jumleditor.view.common.GraphView;
import ru.amse.tsyganov.jumleditor.view.common.StateView;
import ru.amse.tsyganov.jumleditor.view.preferences.Images;

public class Validator {
	
	public final static String ERROR = "Error";
	
	public final static String WARNING = "Warning";
	
	public static ProblemsList validate(
			GraphView<? extends GraphModel> activityGraphView,
			ChartType chartType) {
		
		final ProblemsList problems = new ProblemsList();
		if (chartType == ChartType.ACTIVITY) {
			ActivityGraphValidationVisitor visitor = new ActivityGraphValidationVisitor(
					problems);
			activityGraphView.accept(visitor);
			if (!visitor.initialStateExists()) {
				String message = ERROR
						+ ": diagram does not contain initial state";

				problems.addProblem(new Problem(message, new SelectedItems(),
						Images.getErrorImage()));
			} else {
				Set<StateView> connectedStates = new HashSet<StateView>();
				markConnected(visitor.getInitialStateView(), connectedStates);

				SelectedItems problemSpace = new SelectedItems();

				for (StateView<? extends State> s : activityGraphView
						.getModelViewMap().getStatesMap().values()) {

					if (!connectedStates.contains(s)) {
						problemSpace.selectedStatesAdd(s);
						s.setValidity(Validity.ERROR);
					}
				}

				if (problemSpace.selectedStatesSize() > 0) {
					String message = ERROR
							+ ": states are not accessible from initial state";

					problems.addProblem(new Problem(message, problemSpace,
							Images.getErrorImage()));
				}
			}
		}
		return problems;
	}
	
	private static void markConnected(StateView<? extends State> state,
			Set<StateView> connectedStates) {
		
		if (connectedStates.add(state)) {
			for (Edge t : state.getModel().getStateVertex().getOutgoing()) {
				StateView<? extends State> s = state.getActivityGraphView().
					getModelViewMap().getStatesMap().get(t.getTarget().
							getContainer());
				
				if (s != null) {
					markConnected(s, connectedStates);
				}
			}
		}
		
	}
}
